package com.xiaoshuidi.cloud.module.iot.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.DeviceListByNosApiReqVO;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.PullDeviceApiVo;
import com.xiaoshuidi.cloud.module.iot.common.ResultModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.lyimport.LeiYouDeviceImportListener;
import com.xiaoshuidi.cloud.module.iot.controller.admin.lyimport.LeiYouDeviceImportVo;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.*;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenRequestWrapperModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenResponseWrapperModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.account.CategorysByBrandVo;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.DevicePrice;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.TbAccountDo;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.TbDeviceDo;
import com.xiaoshuidi.cloud.module.iot.dal.repository.DevicePriceRepository;
import com.xiaoshuidi.cloud.module.iot.dal.repository.DeviceRepository;
import com.xiaoshuidi.cloud.module.iot.dal.repository.TbAccountRepository;
import com.xiaoshuidi.cloud.module.iot.dal.repository.TbBrandRepository;
import com.xiaoshuidi.cloud.module.iot.enums.BrandEnum;
import com.xiaoshuidi.cloud.module.iot.enums.RedisTypeEnum;
import com.xiaoshuidi.cloud.module.iot.service.*;
import com.xiaoshuidi.cloud.module.iot.uitils.UUidUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Sky
 * create 2019/05/28
 * email sky.li@ixiaoshuidi.com
 **/
@Service
public class LocalDeviceServiceImpl implements LocalDeviceService {

    private final static Logger LOGGER = LoggerFactory.getLogger(LocalDeviceServiceImpl.class);

    @Autowired
    private LocalAccessTokenServcie localAccessTokenServcie;

    @Autowired
    private TbAccountRepository tbAccountDataAccess;

    @Autowired
    private TbBrandRepository tbBrandDataAccess;

    @Autowired
    private DeviceRepository deviceDataAccess;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private DevicePriceRepository devicePriceAccess;



    /**
     * 根据第三方login_name,login_key 拉取设备并存入IOT库
     *
     * @param tbAccountModels
     * @return
     */
    @Override
    public ResultModel saveDeviceListToIOTByLnLk(List<TbAccountDo> tbAccountModels) throws Exception {
        LOGGER.info("根据第三方login_name,login_key 拉取设备并存入IOT库,请求数据:{}", JSONObject.toJSONString(tbAccountModels));
        for (TbAccountDo tbAccountModel : tbAccountModels) {
            String key = new StringBuilder().append(RedisTypeEnum.SDIOT_APINOPULLDEVICE.getCode()).append(tbAccountModel.getLoginName()).append(tbAccountModel.getLoginKey()).toString();
            if (cacheService.setIfAbsent(key, tbAccountModel.getLoginKey())) {
                //30分钟该api账号不能拉取设备
                cacheService.expire(key, 1800);
                String brandNo = tbAccountModel.getBrandNo();
                ThirdInstanceService thirdInstanceService = ThirdInstanceFactory.produce(brandNo);
                if (thirdInstanceService != null) {
                    AccessTokenRequestWrapperModel requestWrapperModel = new AccessTokenRequestWrapperModel();
                    requestWrapperModel.setApiNo(tbAccountModel.getApiNo());
                    ResultModel<AccessTokenResponseWrapperModel> accessTokenResultModel = localAccessTokenServcie.getAccessToken(requestWrapperModel);
                    LOGGER.info("拉取设备-获取token,返回结果:{}", JSONObject.toJSONString(accessTokenResultModel));
                    //获取token成功
                    if (ResultModel.CODE_SUCCESS.equals(accessTokenResultModel.getCode())) {
                        AccessTokenResponseWrapperModel tokenData = accessTokenResultModel.getData();
                        PullThirdDeviceRequestModel pullThirdDeviceRequestModel = new PullThirdDeviceRequestModel();
                        pullThirdDeviceRequestModel.setLoginName(tbAccountModel.getLoginName());
                        pullThirdDeviceRequestModel.setAccessToken(tokenData.getAccessToken());
                        pullThirdDeviceRequestModel.setLoginKey(tbAccountModel.getLoginKey());
                        pullThirdDeviceRequestModel.setTbAccountDo(tbAccountModel);
                        //调用各个品牌具体拉取设备
                        List<TbDeviceDo> thirdDeviceList = thirdInstanceService.getDevice(pullThirdDeviceRequestModel);
                        //查询这个账号下水滴IOT有的设备
                        List<TbDeviceDo> localDeviceList = deviceDataAccess.getDeviceListByOneApiNo(tbAccountModel.getApiNo());
                        //水滴有，第三方没有设备集合(iot内该删除的设备)
                        List<TbDeviceDo> deletedDeviceList = localDeviceList.stream().filter(tbDeviceDo -> !thirdDeviceList.stream().map
                                (thirdDevice -> thirdDevice.getDeviceThirdNo()).collect(Collectors.toList()).contains(tbDeviceDo.getDeviceThirdNo())).collect(Collectors.toList());
                        //第三方有，水滴没有设备集合(iot内该添加的设备)
                        List<TbDeviceDo> addedDeviceList = null;
                        if (!BrandEnum.SHANGTANG.getBrand().equals(brandNo)) {
                            addedDeviceList = thirdDeviceList.stream().filter(tbDeviceDo -> !localDeviceList.stream().map
                                    (localDevice -> localDevice.getDeviceThirdNo()).collect(Collectors.toList()).contains(tbDeviceDo.getDeviceThirdNo())).collect(Collectors.toList());
                        } else {
                            addedDeviceList = thirdDeviceList.stream().filter(tbDeviceDo -> !localDeviceList.stream().map
                                    (localDevice -> localDevice.getDeviceName()).collect(Collectors.toList()).contains(tbDeviceDo.getDeviceName())).collect(Collectors.toList());
                        }
                        for (TbDeviceDo tbDeviceDo : addedDeviceList) {
                            tbDeviceDo.setBrandNo(brandNo);
                            tbDeviceDo.setBrandName(tbAccountModel.getBrandName());
                            tbDeviceDo.setApiNo(tbAccountModel.getApiNo());
                            tbDeviceDo.setDeviceNo(UUidUtils.generateUuid());
                            tbDeviceDo.setStatus(1);
                        }
                        //删除设备列表
//                        if (deletedDeviceList != null && deletedDeviceList.size() != 0) {
//                            int deleteResult = deviceDataAccess.deleteDeviceList(deletedDeviceList);
//                            LOGGER.info("saveDeviceListToIOTByLnLk,删除设备列表,result：{}", deleteResult);
//                        }
                        if (addedDeviceList != null && addedDeviceList.size() != 0) {
                            //添加设备到数据库
                            boolean addResult = deviceDataAccess.saveBatch(addedDeviceList);
                            try {
                                //设备信息初始化操作（不同品牌，初始化操作也不一样，异步操作）
                                LOGGER.info("设备信息初始化操作（不同品牌，初始化操作也不一样，异步操作)集合:{}", JSONObject.toJSONString(addedDeviceList));
                                List<TbDeviceDo> tbDeviceDoList = thirdInstanceService.initializeDeviceInfo(addedDeviceList, pullThirdDeviceRequestModel);
                            } catch (Exception e) {
                                e.printStackTrace();
                                LOGGER.error(" thirdInstanceService.initializeDeviceInfo，errorMessage:{}", e.getMessage());
                            }
                        }
                    }
                } else {
                    LOGGER.info(" thirdInstanceService not found");
                }
                //处理完成，清除keyredis锁
                cacheService.deleteObjectByKey(key);
            }
        }
        return ResultModel.createSuccess();
    }


    /**
     * 根据水滴api_no拉取设备并存入IOT库
     *
     * @param apiNos
     * @return
     */
    @Override
    public ResultModel saveDeviceListToIOTByApiNo(List<String> apiNos) throws Exception {
        LOGGER.info("根据水滴api_no拉取设备并存入IOT库,请求数据:{}", JSONObject.toJSONString(apiNos));
        List<TbAccountDo> tbAccountModels = tbAccountDataAccess.getApiListByApiNos(apiNos);
        ResultModel resultModel = this.saveDeviceListToIOTByLnLk(tbAccountModels);
        return resultModel;
    }


    /**
     * 根据品牌编号查询该品牌对接品类
     *
     * @param brandNo
     * @return
     */
    @Override
    public ResultModel<List<CategorysByBrandVo>> getCategoryByBrand(String brandNo) {
        List<CategorysByBrandVo> categorysByBrandVos = tbBrandDataAccess.getCategoryByBrand(brandNo);
        return ResultModel.createSuccess(categorysByBrandVos);
    }

    /**
     * 根据水滴api_no拉取设备列表并展示给第三方
     *
     * @param apiNos
     * @return
     */
    @Override
    public ResultModel<Map<String, List<PullDeviceVo>>> getDeviceListByApiNo(List<String> apiNos) {
        LOGGER.info("根据水滴api_no拉取设备列表并展示给第三方,请求数据:{}", JSONObject.toJSONString(apiNos));
        List<PullDeviceVo> deviceVoList = deviceDataAccess.getDeviceListByApiNo(apiNos);
        Map<String, List<PullDeviceVo>> deviceListMap = deviceVoList.stream().collect(Collectors.groupingBy(PullDeviceVo::getDeviceType, Collectors.toList()));
        return ResultModel.createSuccess(deviceListMap);
    }

    /**
     * 根据device_name模糊查询设备列表（品类）
     *
     * @param tbDeviceDo
     * @return
     */
    @Override
    public ResultModel<List<PullDeviceVo>> getDevcieListByDeviceName(TbDeviceDo tbDeviceDo) {
        LOGGER.info("根据device_name模糊查询设备列表（品类）,请求数据:{}", JSONObject.toJSONString(tbDeviceDo));
        List<PullDeviceVo> pullDeviceVos = deviceDataAccess.getDevcieListByDeviceName(tbDeviceDo);
        return ResultModel.createSuccess(pullDeviceVos);
    }

    /**
     * 根据device_no 列表批量查询设备列表
     *
     * @param deviceListByNosReqVO
     * @return
     */
    @Override
    public ResultModel<List<PullDeviceVo>> getDeviceListByDeviceNos(DeviceListByNosReqVO deviceListByNosReqVO) {
        LOGGER.info("根据device_no 列表批量查询设备列表,请求数据:{}", JSONObject.toJSONString(deviceListByNosReqVO));
        List<PullDeviceVo> pullDeviceVos = Lists.newArrayList();
        List<String> deviceNos = deviceListByNosReqVO.getDeviceNos();
        if (deviceNos != null && deviceNos.size() > 0) {
            pullDeviceVos = deviceDataAccess.getDeviceListByDeviceNos(deviceListByNosReqVO);
        }
        return ResultModel.createSuccess(pullDeviceVos);
    }

    /**
     * 根据device_no 列表,批量清空设备剩余金额
     *
     * @param deviceNos
     * @return
     */
    @Override
    public ResultModel<DeviceChargeFeeClearResVO> setChargeFeeClear(List<DeviceChargeFeeClearReqVO> deviceNos) {
        LOGGER.info("根据device_no 列表,批量清空设备剩余金额,请求数据:{}", JSONObject.toJSONString(deviceNos));
        List<String> nos = deviceNos.stream().map(s -> s.getDeviceNo()).collect(Collectors.toList());
        int updateResult = deviceDataAccess.updateRemainingAmountClear(nos);
        return ResultModel.createSuccess();
    }

    /**
     * 请求第三方获取第三方数据库中水电表读数
     *
     * @param deviceGetDailyPowerReqModel
     * @return
     */
    @Override
    public ResultModel<List<DeviceGetDailyPowerResModel>> getDailyPower(DeviceGetDailyPowerReqModel deviceGetDailyPowerReqModel) throws Exception {
        //获取该设备对应的第三方设备的apiNo
        String apiNo = deviceGetDailyPowerReqModel.getApiNo();
        //获取第三方id集合
        List<String> deviceThirdNoList = deviceGetDailyPowerReqModel.getDeviceThirdNo();
        AccessTokenRequestWrapperModel requestWrapperModel = new AccessTokenRequestWrapperModel();
        requestWrapperModel.setApiNo(apiNo);
        ResultModel<AccessTokenResponseWrapperModel> accessTokenResultModel = localAccessTokenServcie.getAccessToken(requestWrapperModel);
        LOGGER.info("请求第三方获取第三方数据库中水电表读数-获取token,返回结果:{}", JSONObject.toJSONString(accessTokenResultModel));
        //获取token成功
        if (ResultModel.CODE_SUCCESS.equals(accessTokenResultModel.getCode())) {
            AccessTokenResponseWrapperModel accessTokenResultModelData = accessTokenResultModel.getData();
            OperateThirdDeviceRequestModel operateThirdDeviceRequestModel = new OperateThirdDeviceRequestModel();
            operateThirdDeviceRequestModel.setLoginName(accessTokenResultModelData.getAppId());
            operateThirdDeviceRequestModel.setLoginKey(accessTokenResultModelData.getAppKey());
            operateThirdDeviceRequestModel.setAccessToken(accessTokenResultModelData.getAccessToken());
            operateThirdDeviceRequestModel.setDeviceThirdNoList(deviceThirdNoList);
            operateThirdDeviceRequestModel.setDeviceThirdNo(deviceGetDailyPowerReqModel.getThirdNo());
            operateThirdDeviceRequestModel.setQueryBeginTime(deviceGetDailyPowerReqModel.getQueryBeginTime());
            operateThirdDeviceRequestModel.setQueryEndTime(deviceGetDailyPowerReqModel.getQueryEndTime());
            ThirdInstanceService thirdInstanceService = ThirdInstanceFactory.produce(deviceGetDailyPowerReqModel.getBrandNo());
            List<DeviceGetDailyPowerResModel> dailyPower = thirdInstanceService.getDailyPower(operateThirdDeviceRequestModel);
            return ResultModel.createSuccess(dailyPower);
        } else {
            return ResultModel.createFail(accessTokenResultModel.getCode(), accessTokenResultModel.getMsg());
        }
    }

    /**
     * 根据device_no 列表,批量入住退租
     *
     * @param deviceResideListReqVOS
     * @return
     */
    @Override
    public ResultModel<DeviceResideListResVO> setListResideStatus(List<DeviceResideListReqVO> deviceResideListReqVOS) throws Exception {
        LOGGER.info("根据device_no 列表,批量入住退租,请求数据:{}", JSONObject.toJSONString(deviceResideListReqVOS));
        for (DeviceResideListReqVO deviceResideListReqVO : deviceResideListReqVOS) {
            TbDeviceDo tbDeviceDo = deviceDataAccess.getDeviceByDeviceNo(deviceResideListReqVO.getDeviceNo());
            LOGGER.info("入住退租前剩余金额,设备编号:{},操作状态:{}", tbDeviceDo.getDeviceNo(), deviceResideListReqVO.getResideStatus());
            String brandNo = tbDeviceDo.getBrandNo();

        }
        return ResultModel.createSuccess();
    }


    /**
     * 根据device_no 列表批量分页查询设备列表
     *
     * @param deviceListByNosReqVO
     * @return
     */
    @Override
    public ResultModel<PageInfo<PullDeviceApiVo>> findDeviceListByDeviceNosPage(DeviceListByNosApiReqVO deviceListByNosReqVO) {
        LOGGER.info("根据device_no 列表批量分页查询设备列表,请求数据:{}", JSONObject.toJSONString(deviceListByNosReqVO));
        PageInfo<PullDeviceApiVo> pullDeviceVos = new PageInfo<>();
        List<String> deviceNos = deviceListByNosReqVO.getDeviceNos();
        if (deviceNos != null && deviceNos.size() > 0) {
            pullDeviceVos = deviceDataAccess.findDeviceListByDeviceNosPage(deviceListByNosReqVO);
        }
        return ResultModel.createSuccess(pullDeviceVos);
    }

    /**
     * 根据device_no 列表批量查询设备列表
     *
     * @param deviceListByNosReqVO
     * @return
     */
    @Override
    public ResultModel<List<PullDeviceVo>> findDeviceListByDeviceNos(DeviceListByNosReqVO deviceListByNosReqVO) {
        LOGGER.info("根据device_no 列表批量查询设备列表,请求数据:{}", JSONObject.toJSONString(deviceListByNosReqVO));
        List<PullDeviceVo> pullDeviceVos = Lists.newArrayList();
        List<String> deviceNos = deviceListByNosReqVO.getDeviceNos();
        if (deviceNos != null && deviceNos.size() > 0) {
            pullDeviceVos = deviceDataAccess.findDeviceListByDeviceNos(deviceListByNosReqVO);
        }
        return ResultModel.createSuccess(pullDeviceVos);
    }

    @Override
    public DevicePrice getCurrentReading(String deviceNo) {
        LOGGER.info("根据device_no 查询年度总度数,请求数据:{}", deviceNo);
        Calendar now = Calendar.getInstance();
        int year = now.get(Calendar.YEAR);
        DevicePrice devicePrice = devicePriceAccess.getDevicePriceVo(Long.valueOf(year), deviceNo);
        return devicePrice;
    }

    @Override
    public ResultModel<List<PullDeviceApiVo>> findDeviceList(DeviceListByNosApiReqVO deviceListByNosReqVO) {
        LOGGER.info("根据设备在线状态或电池电量批量查询设备列表,请求数据:{}", JSONObject.toJSONString(deviceListByNosReqVO));
        List<PullDeviceApiVo> pullDeviceVos =deviceDataAccess.findDeviceList(deviceListByNosReqVO);
        return ResultModel.createSuccess(pullDeviceVos);
    }

    @Override
    public ResultModel saveLeiYouDeviceFromExcel(String apiNo, MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(), LeiYouDeviceImportVo.class, new LeiYouDeviceImportListener(deviceDataAccess, apiNo)).sheet().doRead();
        } catch (IOException e) {
            return ResultModel.createNativeFail("文件读取异常");
        }
        return ResultModel.createSuccess();
    }

}
